
package com.shop.cloud.live.admin.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shop.cloud.common.core.constant.CacheConstants;
import com.shop.cloud.live.admin.service.LiveRoomSpuService;
import com.shop.cloud.live.common.constant.LiveRoomStatusType;
import com.shop.cloud.live.common.entity.LiveRoom;
import com.shop.cloud.live.admin.mapper.LiveRoomMapper;
import com.shop.cloud.live.admin.service.LiveRoomService;
import com.shop.cloud.live.common.entity.LiveRoomSpu;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 直播间
 *
 * @author
 * @date 2025-01-09 10:53:37
 */
@Service
@AllArgsConstructor
public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomMapper, LiveRoom> implements LiveRoomService {

    private final LiveRoomSpuService liveRoomSpuService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save2(LiveRoom entity) {
        checkLiveRoom(entity);
        super.save(entity);
        doLiveRoomSpu(entity);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = CacheConstants.LIVE_ROOM_CACHE, key = "#id")
    public boolean removeById2(Serializable id) {
        //删除关联
        liveRoomSpuService.remove(Wrappers.<LiveRoomSpu>lambdaQuery()
                .eq(LiveRoomSpu::getRoomId,id));
        return super.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = CacheConstants.LIVE_ROOM_CACHE, key = "#entity.id")
    public boolean updateById2(LiveRoom entity) {
        checkLiveRoom(entity);
        //删除关联
        liveRoomSpuService.remove(Wrappers.<LiveRoomSpu>lambdaQuery()
                .eq(LiveRoomSpu::getRoomId,entity.getId()));
        doLiveRoomSpu(entity);
        return super.updateById(entity);
    }

    @Override
    @CacheEvict(value = CacheConstants.LIVE_ROOM_CACHE, key = "#entity.id")
    public boolean updateById(LiveRoom entity) {
        return super.updateById(entity);
    }

    /**
     * 校验直播间合法性
     */
    protected void checkLiveRoom(LiveRoom entity){
        // 校验时间
        LocalDateTime startTime = entity.getStartTime();
        LocalDateTime endTime = entity.getEndTime();
        if(startTime == null && endTime == null){
            return;
        }
        if (startTime.compareTo(LocalDateTime.now()) < 0) {
            throw new RuntimeException("开始时间不能小于当前时间");
        }
        if (startTime.compareTo(endTime) > 0) {
            throw new RuntimeException("开始时间不能大于结束时间");
        }
        boolean expiredEndTime = LocalDateTimeUtil.isIn(endTime, startTime, LocalDateTimeUtil.offset(startTime, 30, ChronoUnit.MINUTES)) ||
                !LocalDateTimeUtil.isIn(endTime, startTime, LocalDateTimeUtil.offset(startTime, 24, ChronoUnit.HOURS));
        if (expiredEndTime) {
            throw new RuntimeException("开始和结束时间间隔必须大于30分钟，不得超过24小时");
        }
        long countByShop = baseMapper.selectCount(Wrappers.<LiveRoom>lambdaQuery()
                .ne(LiveRoom::getLiveStatus, LiveRoomStatusType.OFFLINE.value())
                .eq(LiveRoom::getShopId, entity.getShopId())
                .and(lw -> lw // 组合时间范围条件
                        .or(orWrapper -> orWrapper // 第一个OR条件：开始时间在区间内
                                .ge(LiveRoom::getStartTime, startTime)
                                .le(LiveRoom::getStartTime, endTime))
                        .or(orWrapper -> orWrapper // 第二个OR条件：区间包含整个直播时间段
                                .le(LiveRoom::getStartTime, startTime)
                                .ge(LiveRoom::getEndTime, endTime))
                        .or(orWrapper -> orWrapper // 第三个OR条件：结束时间在区间内
                                .ge(LiveRoom::getEndTime, startTime)
                                .le(LiveRoom::getEndTime, endTime))
                )
        );
        if (countByShop > 0) {
            throw new RuntimeException("该时间段下已设有直播间，无法再配置新的直播间");
        }
        // 一个主播在一个时间段只能开播一场直播
        long countByUser = baseMapper.selectCount(Wrappers.<LiveRoom>lambdaQuery()
                .ne(LiveRoom::getLiveStatus, LiveRoomStatusType.OFFLINE.value())
                .eq(LiveRoom::getUserId, entity.getUserId())
                .and(lw -> lw // 组合时间范围条件
                        .or(orWrapper -> orWrapper // 第一个OR条件：开始时间在区间内
                                .ge(LiveRoom::getStartTime, startTime)
                                .le(LiveRoom::getStartTime, endTime))
                        .or(orWrapper -> orWrapper // 第二个OR条件：区间包含整个直播时间段
                                .le(LiveRoom::getStartTime, startTime)
                                .ge(LiveRoom::getEndTime, endTime))
                        .or(orWrapper -> orWrapper // 第三个OR条件：结束时间在区间内
                                .ge(LiveRoom::getEndTime, startTime)
                                .le(LiveRoom::getEndTime, endTime))
                )
        );
        if (countByUser > 0) {
            throw new RuntimeException("主播在该时间段下已设有直播间，无法再配置新的直播间");
        }
    }

    /**
     * 添加关联
     * @param entity
     */
    protected void doLiveRoomSpu(LiveRoom entity){
        List<String> goodsSpuIds = entity.getGoodsSpuIds();
        if(goodsSpuIds != null && goodsSpuIds.size() > 0){
            List<LiveRoomSpu> listLiveRoomSpu = goodsSpuIds.stream().map(spuId -> {
                LiveRoomSpu liveRoomSpu = new LiveRoomSpu();
                liveRoomSpu.setSpuId(spuId);
                liveRoomSpu.setRoomId(entity.getId());
                return liveRoomSpu;
            }).collect(Collectors.toList());
            liveRoomSpuService.saveBatch(listLiveRoomSpu);
        }
    }

    @Override
    @Cacheable(value = CacheConstants.LIVE_ROOM_CACHE, key = "#id")
    public LiveRoom getById2(Serializable id) {
        LiveRoom liveRoom = baseMapper.selectById(id);
        if(liveRoom != null){
            List<String> goodsSpuIds = liveRoomSpuService.list(Wrappers.<LiveRoomSpu>query().lambda()
                            .eq(LiveRoomSpu::getRoomId, id))
                    .stream().map(item -> item.getSpuId()).collect(Collectors.toList());
            liveRoom.setGoodsSpuIds(goodsSpuIds);
        }
        return liveRoom;
    }
}
